--region *.lua
--Date
--此文件由[BabeLua]插件自动生成
local PlayScene = class("PlayScene")
local director = cc.Director:getInstance()
local scheduler = director:getScheduler()
local landScheduler, pipeScheduler, birdScheduler = 0, 0, 0

--------------------------准备Layer---------------------
local function readyLayer()
    local layer = cc.Layer:create()

    local ready = display.newSprite("tutorial.png")
        :move(display.center)
        :setTag(TAG.TUTORIAL)
        :addTo(layer)

    display.newSprite("text_ready.png")
        :move(display.cx, display.cy + ready:getContentSize().height)
        :setTag(TAG.TEXT_READY)
        :addTo(layer)
    layer:setVisible(true)

    return layer
end

------------------------碰撞检测的Layer-----------------------
local function spriteLayer()
    local layer = cc.Layer:create()

--  添加计数字体
    local count = cc.LabelAtlas:_create("0", "Counter.plist"):setTag(TAG.COUNT)
    count:setAnchorPoint(0.5, 0.5)
    count:setPosition(cc.p(display.cx, display.cy + count:getContentSize().height * 3))
    count:setGlobalZOrder(1)
    count:setVisible(false)
    count:addTo(layer)
    
--  创建小鸟，添加上下浮动动作，设置物理世界刚体
    local b = createBird()
    b.addSwing()
    b.setPhysic()
    local bird = b.getBird()
    bird:addTo(layer, 2)

--  创建陆地，添加陆地滚动效果
    local l = createLand()
    local land1, land2 = l.getLands()
    local landHeight = land1:getContentSize().height
    landScheduler = scheduler:scheduleScriptFunc(l.setScroll, SPEED.MAP_SCROLL, false)
    land1:addTo(layer, 1)
    land2:addTo(layer, 1)

--  创建碰撞边界，防止小鸟跑出屏幕外
    local border = cc.Node:create()
    local borderWidth, borderHeight = bgWidth, bgHeight - landHeight
    border:setPhysicsBody(cc.PhysicsBody:createEdgeBox(cc.size(borderWidth, borderHeight), cc.PHYSICSBODY_MATERIAL_DEFAULT))
    border:setPosition(display.cx, display.cy + landHeight / 2)
    border:setTag(TAG.BORDER)
    border:addTo(layer)

    return layer
end

--  游戏结束时计算成绩、保存最高分
local function saveScore(score)
    local data = cc.UserDefault:getInstance()
    local best = data:getIntegerForKey("best") or 0
    if best then
        if score > best then
            data:setIntegerForKey("best", score)
        end
    else    
        data:setIntegerForKey("best", score)
        best = score
    end

    return score, best
end

--------------------- 小鸟死亡后的结算界面  ------------------------
local function resultLayer(score, best)
    local layer = cc.Layer:create()
    local blinkScheduler = 0
    local scoreScheduler = 0

    local scorePanel = cc.Sprite:create("score_panel.png")
    scorePanel:setPosition(cc.p(display.cx, display.cy - scorePanel:getContentSize().height * 3))
    scorePanel:addTo(layer)

    local gameOver = cc.Sprite:create("text_game_over.png")
    gameOver:setPosition(cc.p(display.cx, display.cy + scorePanel:getContentSize().height - gameOver:getContentSize().height / 2))
    gameOver:setOpacity(0)
    gameOver:addTo(layer)

--  重新开始游戏的菜单项
    local menu = cc.Menu:create()
    local restart = cc.MenuItemImage:create("button_play.png","button_play.png")
    restart:setName(SCENE.READY)
    restart:registerScriptTapHandler(
    function(name, sender)
        local name = sender:getName()
        local r = require("app.views.scene."..name)
        scheduler:unscheduleScriptEntry(landScheduler)
        scheduler:unscheduleScriptEntry(blinkScheduler)
        scheduler:unscheduleScriptEntry(scoreScheduler)
        director:replaceScene(r.create())
    end
    )    
    restart:addTo(menu)
    menu:setPosition(cc.p(display.cx, display.cy - scorePanel:getContentSize().height + restart:getContentSize().height / 4))
    menu:setVisible(false)
    menu:addTo(layer)

--  本次游戏得分
    local sLabel = cc.LabelAtlas:_create("0", "Score.plist"):setTag(TAG.SCORE)
    local sx = display.cx + scorePanel:getContentSize().width / 2 - sLabel:getContentSize().width * 3
    local sy = display.cy + sLabel:getContentSize().height / 2
    sLabel:setAnchorPoint(0.5, 0)
    sLabel:setPosition(cc.p(sx, sy - scorePanel:getContentSize().height * 3))
    sLabel:addTo(layer, 1)

--  最高分
    local bLabel = cc.LabelAtlas:_create(best, "Score.plist")
    bLabel:setAnchorPoint(0.5, 0)
    bLabel:setPosition(cc.p(sx, sy - bLabel:getContentSize().height * 2 - scorePanel:getContentSize().height * 3))
    bLabel:addTo(layer, 1)
    
--  计分板动画
    local time = 0.5
    gameOver:runAction(cc.Sequence:create(cc.DelayTime:create(time), cc.FadeIn:create(0.5)))
    time = time + 0.5
    local function showUp(node)
        return cc.Sequence:create(cc.DelayTime:create(time), cc.CallFunc:create(
            function()
                node:runAction(cc.MoveBy:create(0.6, cc.p(0, scorePanel:getContentSize().height * 3)))
            end
            ))
    end
    scorePanel:runAction(showUp(scorePanel))
    sLabel:runAction(showUp(sLabel))
    bLabel:runAction(showUp(bLabel))
    time = time + 1

--  根据得分判定是否颁发奖章，同时为奖章添加闪光帧动画
    local function award()
        local m = cc.exports.createMedal(score, best)
        
        if m then
            local medal = m.getMedal()
            medal:setTag(TAG.MEDAL)
            medal:setPosition(cc.p(display.cx - medal:getContentSize().width * 1.5, 
                                    display.cy - medal:getContentSize().height / 8))
            medal:addTo(layer, 1)

            local blink = m.getBlink()
            blink:setPosition(medal:getPosition())
            blink:setVisible(false)
            blink:addTo(layer, 2)
            blinkScheduler = scheduler:scheduleScriptFunc(m.blinking, 0.2, false)
        end
    end

--  本次游戏得分的动画播放完毕后颁发奖章
    local function countScore(delta)
        if sLabel:getString() - '0' == score then 
            scheduler:unscheduleScriptEntry(scoreScheduler)
            award()
        else sLabel:setString(sLabel:getString() + 1)
        end
    end
    menu:runAction(cc.Sequence:create(cc.DelayTime:create(time), cc.CallFunc:create(
    function()
        menu:setVisible(true)
        scoreScheduler = scheduler:scheduleScriptFunc(countScore, 0.2, false)
    end
    )))
    
    return layer
end

-------------------创建场景----------------------
function PlayScene.create()
    local scene = cc.Scene:createWithPhysics()
    scene:getPhysicsWorld():setGravity(cc.p(0, GRAVITY))

    display.newSprite("bg_day.png")
        :move(display.center)
        :addTo(scene, BGz, TAG.BG)
    local ready = readyLayer()
    local sprite = spriteLayer()
    local bird = sprite:getChildByTag(TAG.BIRD)
    scene:addChild(ready, BGz + 1)
    scene:addChild(sprite, SPRITEz, TAG.SPRITE)

    local mouselistener = cc.EventListenerTouchOneByOne:create()
    local contactListener = cc.EventListenerPhysicsContact:create()
    local isDead = false

--  小鸟死亡判定
    local function die()
    --  取消触摸事件，停止管道和陆地滚动，屏幕闪烁
        director:getEventDispatcher():removeEventListener(mouselistener)
        scheduler:unscheduleScriptEntry(pipeScheduler)
        scheduler:unscheduleScriptEntry(landScheduler)
        local bg = director:getRunningScene():getChildByTag(TAG.BG)
        bg:runAction(cc.Blink:create(0.1, 1))
        isDead = true
    end
        
--  根据小鸟的当前速度设置旋转角度
    local land = sprite:getChildByTag(TAG.LAND)
    local deadY = land:getPositionY() + land:getContentSize().height + bird:getContentSize().height / 2
    local function birdRotate(delta)
        local Vy = bird:getPhysicsBody():getVelocity().y
        local angle = -Vy * 0.09
        if angle >= 90 then
            angle = 90
        end
        bird:setRotation(angle)
    --  直到小鸟落地，停止动作并弹出结算界面
        if bird:getPositionY() <=  deadY then
            bird:setRotation(90)
            bird:stopAllActions()
            bird:getPhysicsBody():setVelocity(cc.p(0, 0))
            scheduler:unscheduleScriptEntry(birdScheduler)

            if isDead == false then
                die()
            end
            local count = sprite:getChildByTag(TAG.COUNT)
            count:setVisible(false)
            local result = resultLayer(saveScore(count:getString() - '0'))
            director:getRunningScene():addChild(result, SPRITEz + 1, TAG.RESULT)
        end
    end
    
    local function onTouchBegan(touch, event)
    --  首次触摸，隐藏准备界面，开始计分，初始化管道
        if ready then
            ready:getChildByTag(TAG.TUTORIAL):runAction(cc.FadeOut:create(0.5))
            ready:getChildByTag(TAG.TEXT_READY):runAction(cc.FadeOut:create(0.5))
            ready = nil
            local count = sprite:getChildByTag(TAG.COUNT)
            count:setVisible(true)

            bird:stopActionByTag(TAG.SWING)
            bird:getPhysicsBody():setGravityEnable(true)
            birdScheduler = scheduler:scheduleScriptFunc(birdRotate, SPEED.BIRD_ROTATE, false)

            local p = cc.exports.createPipes()
            p.reset()
            p.addPipes()
            pipeScheduler = scheduler:scheduleScriptFunc(p.pipesScroll, SPEED.MAP_SCROLL, false)
        end

    --  每次触摸给予小鸟一个向上的速度
        bird:getPhysicsBody():setVelocity(cc.p(0, VELOCITY))
        return true
    end

    local function onTouchEnded(touch, event)
        return true
    end

    --  碰撞检测
    local function onContactBegin(contact)
        if isDead == false then
            print("Contact starts...")
            local spriteA = contact:getShapeA():getBody():getNode()
            local spriteB = contact:getShapeB():getBody():getNode()
        
            if (TAG.BIRD == spriteA:getTag() and TAG.PIPE == spriteB:getTag()) then
                spriteB:getPhysicsBody():setEnabled(false)
                die()
            end
            return true
        end
    end
    
    contactListener:registerScriptHandler(onContactBegin, cc.Handler.EVENT_PHYSICS_CONTACT_BEGIN)
    local eventDispatcher = sprite:getEventDispatcher()
    eventDispatcher:addEventListenerWithSceneGraphPriority(contactListener, sprite)

    mouselistener:setSwallowTouches(true)
    mouselistener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
    mouselistener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED )
    local eventDispatcher = scene:getEventDispatcher()
    eventDispatcher:addEventListenerWithSceneGraphPriority(mouselistener, scene)
    
    scene = cc.TransitionFade:create(1, scene)
    return scene
end

return PlayScene
--endregion
